package com.cx.purchase.plan.service;


import com.cx.purchase.config.ResultVO;
import com.cx.purchase.config.ResultVOBuilder;
import com.cx.purchase.plan.mapper.PlanclassMapper;
import com.cx.purchase.plan.model.*;
import com.cx.purchase.plan.model.*;
import com.cx.purchase.subclass.model.SubClassAddVo;
import com.cx.purchase.util.AllrecordsVo;
import com.cx.purchase.util.ExportUtil;
import com.cx.purchase.util.POIClass;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
@Service
public class PlanServiceImpl implements PlanService {
    @Autowired
    private PlanclassMapper subClassMapper;
    @Override
    public ResultVO queryPage(PlanClassSelectVo planClassSelectVo) {


        List<PlanClass> subClassVoList = subClassMapper.queryData(planClassSelectVo);

        for (PlanClass planClass :
        subClassVoList) {
            if (planClass.getStatus()) {
                planClass.setStatusName("启用");
            }else{
                planClass.setStatusName("禁用");
            }

        }
        int count =  subClassMapper.queryCount(planClassSelectVo);

        AllrecordsVo allrecordsVo = new AllrecordsVo();
        allrecordsVo.setPageIndex(planClassSelectVo.getPageIndex());
        allrecordsVo.setPageSize(planClassSelectVo.getPageSize());
        allrecordsVo.setTotalNumber(count);
        allrecordsVo.setDataList(subClassVoList);
        allrecordsVo.resettotalNum(count);
        return ResultVOBuilder.success(allrecordsVo);

    }

    @Override
    @Transactional
    public ResultVO add(@Valid PlanClassAddVo planClassAddVo) {
        //验证传过来的编码或者名称是否在数据库中已经存在
        //如果存在提示前端错误消息
        PlanClass planClass = subClassMapper.queryByCode(planClassAddVo.getCode());
        if(planClass !=null){
            return ResultVOBuilder.error("已存在改编码,请检查数据");
        }
        PlanClass planClassName = subClassMapper.queryByName(planClassAddVo.getName());
        if(planClassName !=null){
            return ResultVOBuilder.error("已存在该名称,请检查数据");
        }
        //入库
        //由于没用创建人 和修改人  就给他一个
        String name = "张三";
        PlanClass planClass1 = new PlanClass();
        //由于目前对象没有添加的功能所以将添加的功能付给 目前的这个对象
        BeanUtils.copyProperties(planClassAddVo, planClass1);
        planClass1.setCreateName(name);
        planClass1.setCreateTime(new Date());
        planClass1.setUpdateName(name);
        planClass1.setUpdateTime(new Date());

        subClassMapper.add(planClass1);
        return ResultVOBuilder.success(planClass1);
    }

    public ResultVO update(PlanClassUpdateVo planClassUpdateVo) {
        //验证传过来的编码或者名称是否在数据库中已经存在
        //如果存在提示前端错误消息
        PlanClass planClassId = subClassMapper.queryById(planClassUpdateVo.getId());
        if(planClassId ==null){
            return ResultVOBuilder.error("数据不存在,请检查数据");
        }
        PlanClass planClassName = subClassMapper.queryByName(planClassUpdateVo.getName());
        if(planClassName !=null){
            return ResultVOBuilder.error("已存在该名称,请检查数据");
        }
        //入库
        //由于没用创建人 和修改人  就给他一个
        String name = "张三";
        PlanClass planClass1 = new PlanClass();
        //由于目前对象没有添加的功能所以将添加的功能付给 目前的这个对象
        BeanUtils.copyProperties(planClassUpdateVo, planClass1);
        planClass1.setUpdateName(name);
        planClass1.setUpdateTime(new Date());

        subClassMapper.update(planClass1);
        return ResultVOBuilder.success(planClass1);
    }

    public ResultVO queryById(Integer id) {
        //查看数据库中是否又该id
        PlanClass planClassId = subClassMapper.queryById(id);
        if(planClassId ==null){
            return ResultVOBuilder.error("数据不存在,请检查数据");
        }
        return ResultVOBuilder.success(planClassId);
    }

    public ResultVO updateStatus(PlanClassUpdateStatusVo planClassUpdateStatusVo) {
        //验证传过来的编码或者名称是否在数据库中已经存在
        //如果存在提示前端错误消息
        PlanClass planClassId = subClassMapper.queryById(planClassUpdateStatusVo.getId());
        if(planClassId ==null){
            return ResultVOBuilder.error("数据不存在,请检查数据");
        }

        //入库
        //由于没用创建人 和修改人  就给他一个
        String name = "张三";
        PlanClass planClass1 = new PlanClass();
        //由于目前对象没有添加的功能所以将添加的功能付给 目前的这个对象
        BeanUtils.copyProperties(planClassUpdateStatusVo, planClass1);
        planClass1.setUpdateName(name);
        planClass1.setUpdateTime(new Date());

        subClassMapper.updateStatus(planClass1);
        return ResultVOBuilder.success(planClass1);
    }

    /**
     *   2.提示版本问题，询问产品经理支持哪种版本的导入格式，2007版本的导入模板，根据版本不同，poi导入技术的读取方式不同
     3.模板是否是需要导入的模板，验证模板是否正确
     4.格式问题，必须保持统一格式，统一为字符串格式导入
     5.验证不为空字段是否为空
     6.验证字符长度是否符合需求
     7.验证数据是否存在也就是是否合法
     8.验证数据是否重复
     9.对于需要转换的数据进行数据转换，比如数据库存的数据为数字格式，用户输入的为汉字，需要把汉字转换为数字存储

     * @param file
     * @return
     */
    @Override
    public ResultVO importFile(MultipartFile file) throws Exception {
        //怎样验证模板是否正确呢？
        //引入poi读取表格数据，验证内容是否是计划大类的内容。
        //引入poi步骤  1.导包  2.引入xssf工具类完成读取
        ResultVO resultVo = poiImport(file);
        if (!resultVo.isSuccess()){
            return resultVo;
        }

        //数据放入集合中
        List<PlanClassAddVo> All = (List<PlanClassAddVo>) resultVo.getData();


        //有了数据就要验证数据了
        // 5.验证不为空字段是否为空

//        6.验证字符长度是否符合需求
//        7.验证数据是否存在也就是是否合法
//        8.验证数据是否重复
        ResultVO  reAll =  quchong(All);
        if(!reAll.isSuccess()){
            return reAll;
        }


//        9.对于需要转换的数据进行数据转换，比如数据库存的数据为数字格式，用户输入的为汉字，需要把汉字转换为数字存储
        List<PlanClassAddVo> sussceList  = (List<PlanClassAddVo>) reAll.getData();
        for (PlanClassAddVo s : sussceList) {
            if(s.getStatusName().equals("启用")){
                s.setStatus(1);
            }else {
                s.setStatus(0);
            }
        }
        //打印所有的数据进行查看
        System.out.println("看看状态是否改变了"+sussceList);

        //批量入库

//        validateImport(resultVo.getData());
        //批量入库
        //类型转换
//        List<PlanClass> planClass = new ArrayList<>();
//        BeanUtils.copyProperties(sussceList,planClass);


        String name = "张三";
        Date date = new Date();
        for (PlanClassAddVo list:sussceList) {
            list.setUpdateName(name);
            list.setUpdateTime(date);
            list.setCreateName(name);
            list.setCreateTime(date);
        }
        System.out.println("planClass"+sussceList);

        //批量添加到数据库
        subClassMapper.addAll(sussceList);

        return  ResultVOBuilder.success();
    }
//    private ResultVo validateImport(){
//
//    }

    //poi读取信息
    public ResultVO poiImport(MultipartFile file)throws Exception{
        //        3.模板是否是需要导入的模板，验证模板是否正确
        XSSFWorkbook workbook = new XSSFWorkbook(file.getInputStream());
        //获取单元格中的信息 at0是获取sheet1中的数据。
        XSSFSheet sheet = workbook.getSheetAt(0);
        System.out.println(sheet.getRow(sheet.getFirstRowNum()).getCell(0));
        //验证第一列第一行的表格标头信息是否为 “询价单导入”，如果不是，提示模板错误。
        if (!String.valueOf(sheet.getRow(sheet.getFirstRowNum()).getCell(0)).equals("计划大类导入")) {
            return ResultVOBuilder.error("模板错误，请检查模板！");
        }
        //定义一个集合用来存放表格中的数据
        List<PlanClassAddVo> planClassVoList = new ArrayList<>();
        //遍历excel表格中的所有数据，从第五行开始读取，没有数据时终止遍历。
        for (int i = sheet.getFirstRowNum() + 4; i <= sheet.getLastRowNum(); i++) {
            //读取每一行的数据
            XSSFRow xssfRow = sheet.getRow(i);
            if(xssfRow!=null) {
                String test1 = String.valueOf(xssfRow.getCell(1)).trim();
                String test2 = String.valueOf(xssfRow.getCell(2)).trim();
                String test3 = String.valueOf(xssfRow.getCell(3)).trim();
                if (!test1.equals("")&&!test1.equals("null")
                        ||!test2.equals("")&&!test2.equals("null")
                        ||!test3.equals("")&&!test3.equals("null")){
                    //把每一行的数据放入到实体类中
                    ResultVO<PlanClassAddVo> inquiryImportVo = build(xssfRow);
                    if (!inquiryImportVo.isSuccess()){
                        return inquiryImportVo;
                    }
                    //把实体类中的数据放入到list集合中
                    planClassVoList.add(inquiryImportVo.getData());
                }

            }
        }
        return ResultVOBuilder.success(planClassVoList);
    }

    public ResultVO build(XSSFRow xssfRow){
        PlanClassAddVo planClassAddVo = new PlanClassAddVo();
        //        4.格式问题，必须保持统一格式，统一为字符串格式导入
        planClassAddVo.setCode(String.valueOf(xssfRow.getCell(1)));
        planClassAddVo.setName(String.valueOf(xssfRow.getCell(2)));
        planClassAddVo.setStatusName(String.valueOf(xssfRow.getCell(3)));
        planClassAddVo.setRemark(String.valueOf(xssfRow.getCell(4)));
        return ResultVOBuilder.success(planClassAddVo);
    }


    /**
     *查看是否重复或者  为空
     */
    public ResultVO quchong(List<PlanClassAddVo> All){
        //检查文档是否有重复
        List<String> codeList = new ArrayList<>();
        List<String> nameList = new ArrayList<>();

        for (PlanClassAddVo a:All) {
            codeList.add(a.getCode());
            nameList.add(a.getName());
        }
        //去重code
        HashSet<String> codeSet = new HashSet<>(codeList);
        //去重name
        HashSet<String> nameSet = new HashSet<>(nameList);

        //去重后放入集合中
        if(codeList.size()!= codeSet.size()){
            ResultVOBuilder.error("有重复的编码,请检查你的文档");
        }
        if(nameList.size()!=nameSet.size()){
            ResultVOBuilder.error("有重复的名称,请检查你的文档");
        }

        //检查文档与数据库中是否有重复的名称及编码
        //查询数据库里的所有编码以及名称
        List<String> AllCode = subClassMapper.queryCode();
        List<String> AllName = subClassMapper.queryName();

        //将excl表中的编码,名称;加到查出来的编码,名称集合
        for ( String  list:codeList ) {
            AllCode.add(list);
        }
        for ( String  list:nameList ) {
            AllName.add(list);
        }
        //对所有的code去重后比较大小
        HashSet<String> quchongCode = new HashSet<>(AllCode);

        if(quchongCode.size() != AllCode.size()){

            //存放的重复的集合
            List<String> repeatCodeList = new ArrayList<>();
            //存放的不重复的集合
            List<String> codeList2 = new ArrayList<>();

            for (String  a :AllName){
                if (a.contains(a)){
                    //包含证明重复了
                    repeatCodeList.add(a);
                }else {
                    //不包含证明不重复
                    codeList2.add(a);
                }
            }

            return ResultVOBuilder.error("库中已存在相应的编码,文档中重复的编码是"+repeatCodeList);
        }

        //对所有的name去重后比较大小
        HashSet<String> quchongName = new HashSet<>(AllName);

        if(quchongName.size() != AllName.size()){
            //删除
            //存放的重复的集合
            List<String> repeatNameList = new ArrayList<>();
            //存放的不重复的集合
            List<String> nameList2 = new ArrayList<>();

            for (String  a :AllCode){
                if (a.contains(a)){
                    //包含证明重复了
                    repeatNameList.add(a);
                }else {
                    //不包含证明不重复
                    nameList2.add(a);
                }
            }

            if (repeatNameList.size()>0){
                return ResultVOBuilder.error("库中已存在相应的名称,文档中重复的是"+repeatNameList);
            }

        }
        return ResultVOBuilder.success(All);
    }




    /*
    *计划大类导出
    *
    * */

    @Override
    public ResultVO exportFile(PlanClassSelectVo planClassSelectVo, HttpServletResponse response)throws Exception {
//        第二步使用poi向模板中写入需要导出的数据（限制条数，增加条件导出）
//        第三步把文件响应给浏览器，供给浏览器下载出来。
        List<PlanClass> planClassList = subClassMapper.queryDataExport(planClassSelectVo);
        if (planClassList.size()>10000){
            return ResultVOBuilder.error("导出不允许超过10000条数据");
        }
        //这块代码是公共的
        //获取响应输出流
        ServletOutputStream out = response.getOutputStream();
        //给输出文件设置名称
        POIClass.toPackageOs(response, "计划大类导出");
        //读取模板中的数据
        InputStream in = ExportUtil.toPackageIn("templates/计划大类导出.xlsx");
        //根据模板的数据、把查询出来的数据给摸版SHeet1组中的数据赋值、把excel输出到浏览器上
        writeDataToExcel(in, "Sheet1",planClassList , out);
        if (in != null) {
            in.close();
            out.close();
        }
        return null;
    }

    // 由于此方法不能通用, 所以单独写在这里
    private void writeDataToExcel(InputStream in, String sheetName,
                                  List<PlanClass> resultList, ServletOutputStream out) throws Exception {
        //POi读取模板
        XSSFWorkbook wb = new XSSFWorkbook(in);
        //读取sheet1中的数据
        Sheet sheet = wb.getSheet(sheetName);
        if (sheet != null) {
            //向sheet1中赋值，设置样式
            toResultListValueInfo(sheet, resultList);
        }
        //把数据写入到输出流中
        wb.write(out);
        //关闭poi方法
        wb.close();
    }

    /**
     * 插入excel表中项目信息
     *
     * @param sheet
     */
    private void toResultListValueInfo(Sheet sheet, List<PlanClass> plantList) {
        //从第4行开始赋值
        int row_column = 4;
        int xuhao =1;
        //遍历数据集合
        for (PlanClass obj : plantList) {
            //创建一行的方法
            Row row = sheet.createRow(row_column);
            // 给第一列序号赋值赋值
            POIClass.toCellValue(row,0, xuhao + "");
            // 给第二列编码赋值
            POIClass.toCellValue(row, 1, obj.getCode() + "");
            // 给第3列名称赋值
            POIClass.toCellValue(row, 2, obj.getName() + "");
            // 给状态赋值
            if(obj.getStatus()){
                obj.setStatusName("启用");
            }else {
                obj.setStatusName("禁用");
            }
            POIClass.toCellValue(row, 3, obj.getStatusName() + "");
            //给描述赋值
            POIClass.toCellValue(row, 4, obj.getRemark() + "");
            row_column++;
            xuhao++;
        }
    }

}
